package com.xiaoshuidi.cloud.module.iot.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSONObject;
import com.xiaoshuidi.cloud.framework.common.pojo.CommonResult;
import com.xiaoshuidi.cloud.module.iot.common.ResultModel;
import com.xiaoshuidi.cloud.module.iot.dal.model.ammeter.AmmeterSwitchOnOffReqVO;
import com.xiaoshuidi.cloud.module.iot.dal.model.ammeter.AmmeterSwitchOnOffResVO;
import com.xiaoshuidi.cloud.module.iot.dal.model.callback.SendMessageVo;
import com.xiaoshuidi.cloud.module.iot.dal.model.device.TbDeviceDosageCallbackModel;
import com.xiaoshuidi.cloud.module.iot.dal.model.watermeter.WaterMeterSwitchOnOffReqVO;
import com.xiaoshuidi.cloud.module.iot.dal.model.watermeter.WaterMeterSwitchOnOffResVO;
import com.xiaoshuidi.cloud.module.iot.dal.pojo.*;
import com.xiaoshuidi.cloud.module.iot.dal.repository.*;
import com.xiaoshuidi.cloud.module.iot.dal.util.SendMqMessageUtil;
import com.xiaoshuidi.cloud.module.iot.enums.DeviceTypeEnum;
import com.xiaoshuidi.cloud.module.iot.enums.WaterElectricityReportType;
import com.xiaoshuidi.cloud.module.iot.service.AmmeterService;
import com.xiaoshuidi.cloud.module.iot.service.LocalCallbackService;
import com.xiaoshuidi.cloud.module.iot.service.WaterElectricityReportService;
import com.xiaoshuidi.cloud.module.iot.service.WaterMeterService;
import com.xiaoshuidi.cloud.module.iot.uitils.DateUtils;
import com.xiaoshuidi.cloud.module.rooms.api.sdiot.IotRoomDeviceApi;
import com.xiaoshuidi.cloud.module.rooms.vo.PriceInfo;
import com.xiaoshuidi.cloud.module.rooms.vo.RoomSdiotDeviceMappingVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.stream.function.StreamBridge;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * @author Sky
 * create 2019/06/18
 * email sky.li@ixiaoshuidi.com
 **/
@Service
public class LocalCallbackServiceImpl implements LocalCallbackService {

    private Logger LOGGER = LoggerFactory.getLogger(LocalCallbackServiceImpl.class);
    //    private static volatile Producer iotTopicProducer;
    @Autowired
    private DeviceRepository deviceDataAccess;

    @Autowired
    private DeviceDosageRepository deviceDosageDataAccess;

    @Autowired
    private DeviceOperationRepository deviceOperationDataAccess;

    @Autowired
    private TbDoorLockPasswordRepository doorLockPasswordRepository;

    @Autowired
    private DevicePriceRepository devicePriceAccess;

    @Autowired
    private IotRoomDeviceApi roomDeviceApi;

    @Autowired
    AmmeterService ammeterService;

    @Autowired
    WaterMeterService waterMeterService;
    @Resource
    private StreamBridge streamBridge;
    @Autowired
    IotRoomDeviceApi iotRoomDeviceApi;
    @Autowired
    private WaterElectricityReportService waterElectricityReportService;

    /**
     * 修改tb_device记录
     *
     * @param tbDeviceDo
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = {Exception.class, Throwable.class})
    public boolean updateTbDeviceRecord(TbDeviceDo tbDeviceDo) throws Exception {
        boolean updateResult = false;
        TbDeviceDo currentDevice = deviceDataAccess.getTbDeviceByConditon(tbDeviceDo);
        if (currentDevice != null) {
            tbDeviceDo.setId(currentDevice.getId());
            updateResult = deviceDataAccess.updateById(tbDeviceDo);
        }
        return updateResult;
    }

    /**
     * 电量水量回调记录处理
     *
     * @param tbDeviceDosageCallbackModel
     * @return
     */
    @Override
    public void disposeDeviceDosage(TbDeviceDosageCallbackModel tbDeviceDosageCallbackModel) {
        TbDeviceDo tbDeviceDo = doDisPoseDeviceDosage(tbDeviceDosageCallbackModel);
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = {Exception.class, Throwable.class})
    public TbDeviceDo doDisPoseDeviceDosage(TbDeviceDosageCallbackModel tbDeviceDosageCallbackModel) {
        TbDeviceDo tbDeviceDo = tbDeviceDosageCallbackModel.getTbDeviceDo();
        TbDeviceDo currentDevice = deviceDataAccess.getTbDeviceByConditon(tbDeviceDo);
        TbDeviceDosageDo tbDeviceDosageDo = tbDeviceDosageCallbackModel.getTbDeviceDosageDo();
        if (null == currentDevice) {
            return null;
        }
        Double doubleReadNumber = tbDeviceDosageDo.getEndAmount();
        if (doubleReadNumber.compareTo(currentDevice.getCurrentReading()) < 0) {
            return null;
        }
        //获取阶梯水电价格 1.获取本年度的总度数 2.根据阶梯配置判断使用哪种价格
        Double readAllAccount = 0.0;
        Calendar now = Calendar.getInstance();
        int year = now.get(Calendar.YEAR);
        DevicePrice devicePrice = devicePriceAccess.getDevicePriceVo(Long.valueOf(year), currentDevice.getDeviceNo());
        //本次抄表用量
        BigDecimal totalAmount = BigDecimal.valueOf(tbDeviceDosageDo.getEndAmount()).subtract(BigDecimal.valueOf(currentDevice.getCurrentReading()));
        LOGGER.info("本次抄表用量：" + JSONObject.toJSONString(totalAmount));
        //记录总度数
        if (null == devicePrice) {
            DevicePrice devicePriceVo = new DevicePrice();
            devicePriceVo.setYear(Long.valueOf(year));
            devicePriceVo.setDeviceThireNo(currentDevice.getDeviceThirdNo());
            devicePriceVo.setDeviceNo(currentDevice.getDeviceNo());
            devicePriceVo.setReadAccount(tbDeviceDosageDo.getEndAmount());
            devicePriceAccess.save(devicePriceVo);
        } else {
            //更新总度数
            readAllAccount = totalAmount.add(BigDecimal.valueOf(devicePrice.getReadAccount())).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
            devicePrice.setReadAccount(readAllAccount);
            devicePriceAccess.updateById(devicePrice);
        }
        //获取本次消费金额
        CommonResult<List<PriceInfo>> infoList = roomDeviceApi.getDevicePrice(currentDevice.getDeviceNo(), currentDevice.getDeviceType());
        BigDecimal accountAmount = SendMqMessageUtil.compute(BigDecimal.valueOf(readAllAccount).subtract(totalAmount), BigDecimal.valueOf(readAllAccount), infoList.getData());
        LOGGER.info("阶梯水电infoList：" + JSONObject.toJSONString(infoList));
        LOGGER.info("本次消费金额：" + JSONObject.toJSONString(accountAmount));
        //第一次读数上传
        long count = deviceDosageDataAccess.countDeviceDosageByDeviceNo(currentDevice.getDeviceNo());
        if (currentDevice.getCurrentReading().compareTo(0.0) == 0) {
            if (count == 0) {
                tbDeviceDosageDo.setStartAmount(tbDeviceDosageDo.getEndAmount());
            } else {
                tbDeviceDosageDo.setStartAmount(currentDevice.getCurrentReading());
            }
        } else {
            tbDeviceDosageDo.setStartAmount(currentDevice.getCurrentReading());
        }
        tbDeviceDosageDo.setTotalAmount(totalAmount.doubleValue());
        tbDeviceDosageDo.setDeviceNo(currentDevice.getDeviceNo());
        tbDeviceDosageDo.setDosageDate(LocalDate.now());
        tbDeviceDosageDo.setAmount(accountAmount.setScale(3, BigDecimal.ROUND_HALF_UP).doubleValue());
        String mesgId = UUID.randomUUID().toString();
        tbDeviceDosageDo.setMesgId(mesgId);
        tbDeviceDosageDo.setTenantId(currentDevice.getTenantId());
        tbDeviceDo.setId(currentDevice.getId());
        tbDeviceDo.setDeviceNo(currentDevice.getDeviceNo());
        tbDeviceDo.setCurrentReading(tbDeviceDosageDo.getEndAmount());
        tbDeviceDo.setReportTime(tbDeviceDosageDo.getCreateTime());
        tbDeviceDo.setDeviceType(currentDevice.getDeviceType());
        //有数据上报说明在线(针对合房的银通物联，也会指定状态)
        if (null != tbDeviceDosageCallbackModel.getOnlineStatus()) {
            tbDeviceDo.setOnlineStatus(1);
        } else {
            tbDeviceDo.setOnlineStatus(tbDeviceDosageCallbackModel.getOnlineStatus());
        }
        //当不指定通断电状态时，不对通断电状态做变更
        if (null != tbDeviceDosageCallbackModel.getPowerStatus()) {
            tbDeviceDo.setPowerStatus(tbDeviceDosageCallbackModel.getOnlineStatus());
        }
        tbDeviceDo.setVersion(currentDevice.getVersion());
        //处理剩余电量或者水量
        //tbDeviceDo.setRemainingAmount(BigDecimal.valueOf(currentDevice.getRemainingAmount()).subtract((totalAmount.multiply(BigDecimal.valueOf(currentDevice.getPrice())))).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
        boolean updateTbDeviceRecord = deviceDataAccess.updateTbDeviceRecordAndVersion(tbDeviceDo);
        //发送消息到钱包更新余额
        ResultModel<RoomSdiotDeviceMappingVo> resultModel = iotRoomDeviceApi.getRoomInfoByDeviceNo(currentDevice.getDeviceNo(), currentDevice.getDeviceType());
        LOGGER.info("根据deviceNo获取房间信息：" + JSONObject.toJSONString(resultModel));
        if(resultModel.getCode().equals("0")) {
            Long roomId = resultModel.getData().getRoomHouseId();
            if (CollectionUtil.isNotEmpty(infoList.getData()) && totalAmount.compareTo(BigDecimal.ZERO) > 0) {
                SendMessageVo messageVo = new SendMessageVo();
                messageVo.setAmount(accountAmount.setScale(3, BigDecimal.ROUND_HALF_UP).doubleValue());
                messageVo.setDevice(tbDeviceDo.getDeviceNo());
                messageVo.setMsgId(mesgId);
                messageVo.setRoomId(roomId.toString());
                messageVo.setTradeTime(new Date());
                if (tbDeviceDo.getDeviceType().equals("ammeter")) {
                    messageVo.setCharging("电费");
                } else {
                    messageVo.setCharging("水费");
                }

                LOGGER.info("发送钱包数据：" + JSONObject.toJSONString(messageVo));
                boolean send = streamBridge.send("financeAccountBalance-out-0", MessageBuilder.withPayload(messageVo).setHeader("TAGS", "DEDUCT").build());
                LOGGER.info("发送钱包返回：" + JSONObject.toJSONString(send));
            }
            if (updateTbDeviceRecord) {
                if (totalAmount.compareTo(BigDecimal.ZERO) > 0) {
                    //产生报表数据
                    String type;
                    if (currentDevice.getDeviceType().equals(DeviceTypeEnum.AMMETER.getCode())) {
                        type = WaterElectricityReportType.ELECTRICITY.getCode();
                    } else if (currentDevice.getDeviceType().equals(DeviceTypeEnum.HOT_WATERMETE_TYPE_ENUM.getCode())) {
                        type = WaterElectricityReportType.HOT_WATER.getCode();
                    } else {
                        type = WaterElectricityReportType.COLD_WATER.getCode();
                    }
                    waterElectricityReportService.save(roomId, currentDevice.getDeviceNo(), currentDevice.getDeviceThirdNo(), tbDeviceDosageDo, type, currentDevice.getTenantId());
                }
                //新增读数上报记录
                deviceDosageDataAccess.save(tbDeviceDosageDo);
            } else {
                LOGGER.error("数据上报数据处理失败,版本version冲突,设备编号:{},设备名称:{}", currentDevice.getDeviceNo(), currentDevice.getDeviceName());
            }
        }
        return tbDeviceDo;
    }

    /**
     * 处理预付费断电逻辑
     *
     * @param tbDeviceDo
     */
    public void disposePrepaymentLogic(TbDeviceDo tbDeviceDo, BigDecimal account) {
        try {
            //如果在晚上9点到第二天早上9点期间上报，不进行预付费断电逻辑
            SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
            Date nowTime = sdf.parse(sdf.format(new Date()));
            Date beginTime = sdf.parse("21:00:00");
            Date endTime = sdf.parse("09:00:00");
            if (!DateUtils.belongCalendar(nowTime, beginTime, endTime)) {
                if (DeviceTypeEnum.AMMETER.getCode().equals(tbDeviceDo.getDeviceType()) && account.compareTo(BigDecimal.ZERO) < 0) {
                    //调用电表服务断电操作 todo 要改的
                    ResultModel<AmmeterSwitchOnOffResVO> resultModel = ammeterService.setAmmeterSwitchOff(new AmmeterSwitchOnOffReqVO().setDeviceNo(tbDeviceDo.getDeviceNo()));
                    LOGGER.info("回调callback处理预付费断电逻辑,设备编号:{},返回结果：{}", tbDeviceDo.getDeviceNo(), JSONObject.toJSONString(resultModel));
                } else if (DeviceTypeEnum.COLD_WATERMETE_TYPE_ENUM.getCode().equals(tbDeviceDo.getDeviceType()) && account.compareTo(BigDecimal.ZERO) < 0) {
                    ResultModel<WaterMeterSwitchOnOffResVO> resultModel = waterMeterService.setWaterMeterSwitchOff(new WaterMeterSwitchOnOffReqVO().setDeviceNo(tbDeviceDo.getDeviceNo()));
                    LOGGER.info("回调callback处理预付费断冷水逻辑,设备编号:{},返回结果：{}", tbDeviceDo.getDeviceNo(), JSONObject.toJSONString(resultModel));
                } else if (DeviceTypeEnum.HOT_WATERMETE_TYPE_ENUM.getCode().equals(tbDeviceDo.getDeviceType()) && account.compareTo(BigDecimal.ZERO) < 0) {
                    ResultModel<WaterMeterSwitchOnOffResVO> resultModel = waterMeterService.setWaterMeterSwitchOff(new WaterMeterSwitchOnOffReqVO().setDeviceNo(tbDeviceDo.getDeviceNo()));
                    LOGGER.info("回调callback处理预付费断热水逻辑,设备编号:{},返回结果：{}", tbDeviceDo.getDeviceNo(), JSONObject.toJSONString(resultModel));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error("回调callback处理预付费断电逻辑,设备编号：{}，失败原因：{}", tbDeviceDo.getDeviceNo(), e.getMessage());
        }

    }

    @Override
    public void disposeOpenRecordCallback(TbDeviceDosageCallbackModel tbDeviceDosageCallbackModel) throws Exception {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        TbDeviceDo tbDeviceDo = deviceDataAccess.getTbDeviceByConditon(tbDeviceDosageCallbackModel.getTbDeviceDo());
        JSONObject jsonObject = tbDeviceDosageCallbackModel.getOpenRecord();
        //根据device_no、手机号查询密码ID 注：同一个手机号只运行设置一个密码
        TbDoorlockPassword doorlockPassword = doorLockPasswordRepository.getByDeviceNoAndMemberMobile(tbDeviceDo.getDeviceNo(), jsonObject.getString("userId"));
        TbDeviceOperation tbDeviceOperation = new TbDeviceOperation();
        tbDeviceOperation.setDeviceNo(tbDeviceDo.getDeviceNo());
        if (doorlockPassword != null) {
            tbDeviceOperation.setMemberName(doorlockPassword.getId().toString());
        } else {
            TbDoorlockPassword password = doorLockPasswordRepository.getPassWordThirdPassWordId(tbDeviceDo.getDeviceNo(), jsonObject.getString("userId"));
            if (null != password) {
                tbDeviceOperation.setMemberName(password.getId().toString());
            }
        }
        switch (jsonObject.getString("opType")) {
            case "tenantPwd":
                tbDeviceOperation.setMemberType("1");
                break;
            case "dynamicPwd":
                tbDeviceOperation.setMemberType("2");
                break;
            case "bluetoothPwd":
                tbDeviceOperation.setMemberType("3");
                break;
            case "fingerprintPwd":
                tbDeviceOperation.setMemberType("4");
                break;
            case "cardPwd":
                tbDeviceOperation.setMemberType("5");
                break;
            case "offlinePwd":
                tbDeviceOperation.setMemberType("6");
                break;
            default:
                tbDeviceOperation.setMemberType("0");
                break;
        }
        tbDeviceOperation.setOpType(1);
        tbDeviceOperation.setOpTime(jsonObject.getDate("recordTime"));
        tbDeviceOperation.setStatus(1);
        deviceOperationDataAccess.save(tbDeviceOperation);
    }

    /**
     * 据sn查询tb_device记录
     *
     * @param deviceName
     * @return
     */
    @Override
    public TbDeviceDo getTbDeviceByDeviceNameAndBrandNo(String deviceName, String brandNo) {
        return deviceDataAccess.getTbDeviceByDeviceNameAndBrandNo(deviceName, brandNo);
    }


    /**
     * 根据第三方设备ID和品牌查找tb_device
     *
     * @param deviceThirdNo
     * @param brandNo
     * @return
     */
    @Override
    public TbDeviceDo getTbDeviceByConditon(String deviceThirdNo, String brandNo) {
        TbDeviceDo tbDeviceDo = new TbDeviceDo();
        tbDeviceDo.setDeviceThirdNo(deviceThirdNo);
        tbDeviceDo.setBrandNo(brandNo);
        return deviceDataAccess.getTbDeviceByConditon(tbDeviceDo);
    }

    @Override
    public Boolean tianchengUpdateTbDeviceRecord(TbDeviceDo tbDeviceDo) {
        return deviceDataAccess.tianchengUpdateOnlineStatus(tbDeviceDo);
    }
}
